
4.1 변수란 무엇인가? 왜 필요한가?
-
복잡한 애플리케이션이라도 결국, 데이터를 입력받아 처리하고 결과를 출력하는 것이다. 변수는 프로그래밍에서 데이터를 관리하기 위한 핵심 개념.
-
사람이 아래와 같은 식을 계산하기 위해, 10, 20, +기호를 알고 있어야 계산할 수 있듯이,
자바스크립트 엔진이 코드를 계산(평가 evaluation) 하려면, 10,20, +라는 기호(리터럴 literal과 연산자operator) 의 의미를 알고 있어야하며, 10+20이라는 식(표현식expression) 의 의미도 해석 (파싱parsing) 할 수 있어야 한다.
10 + 20
-
위 식의 연산을 수행하기 위해 먼저 연산자의 좌변과 우변의 숫자 값 (피연산자,operand) 를 기억한다. 컴퓨터는 CPU를 통해 연산하고, 메모리를 통해 데이터를 기억한다.
-
메모리(memory) 는 데이터 저장할 수 있는 메모리 셀(memory cell) 집합체
-
메모리 셀 하나 크기는 1바이트(8비트) 이며, 메모리 셀 크기 단위로 데이터를 2진수로 저장하고 읽는다.
-
각 셀은 고유의 메모리 주소(memory address)를 갖고 메모리 주소는 메모리 공간의 위치를 나타내며 메모리 크기만큼 정수로 표현된다. ex) 4GB 메모리는 0부터 4,294,967,294(0x00000000 ~ 0XFFFFFFFF)까지 메모리 주소를 갖는다.
-
컴퓨터는 데이터 종류(숫자, 텍스트, 이미지, 동영상 등)와 상관없이 모든 데이터를 2진수로 처리하며 저장한다.
변수 필요성
-
위의 식에서 10 과 20을 각각 메모리 공간에 저장하고 연산 결과인 30도 저장한다. 하지만, 이 결과 값을 재사용하기 위해선 저장된 메모리 주소를 통해 해당 메모리 공간에 직접 접근하는 방법 밖에 없다.
-
하지만, 메모리 주소를 통해 값 직접 접근하는 방법은 실수로 운영체제 사용 값을 변경할 수 있어 치명적 오류가 발생될 수 있다. 따라서, 자바스크립트는 개발자의 직접적인 메모리 제어를 허용하지 않는다.
-
프로그래밍 언어는 기억하고 싶은 값을 메모리에 저장하고 저장된 값을 재사용하기 위해 변수라는 매커니즘 제공
-
변수(variable) - 하나의 값을 저장하기 위해 확보한 메모리 공간 자체 또는 그 메모리 공간을 식별하기 위해 붙인 이름, 값의 위치를 가리키는 상징적인 이름.
-
변수는 언어의 컴파일러 또는 인터프리터에 의해 값이 저장된 메모리 공간의 주소로 치환되어 실행되어 개발자가 직접 메모리 주소를 통해 값 저장하고 참조할 필요가 없이 변수를 통해 안전하게 값에 접근 가능.
-
10 + 20은 연산을 통해 새로운 값 30을 생성하고 메모리 공간에 저장된다.
-
메모리 공간에 저장된 값을 식별할 수 있는 고유한 이름(result)을 변수 이름(또는 변수명). 변수에 저장된 값(30)을 변수값
var result = 10 + 20;

- 개발자의 의도를 나타내는 명확한 네이밍은 코드를 이해하기 쉽게 만들며 협업과 품질 향상에 도움을 주기 때문에 변수명은 잘 지어야 한다.
4.2 식별자
- 식별자(identifier) - 변수 이름, 메모리 주소에 붙인 이름, 어떤 값을 구별해서 식별할 수 있는 고유한 이름, 메모리 상에 존재하는 어떤 값을 식별할 수 있는 이름
- 식별자는 값이 아니라 메모리 주소를 기억하고 있다.
- 선언(declaration)에 의해 자바스크립트 엔진에 식별자의 존재를 알린다.
4.3 변수 선언
- 변수 선언(variable declaration) - 변수 생성하는 것. 값을 저장하기 위한 메모리 공간을 확보(allocate)하고 변수 이름과 확보된 메모리 공간의 주소를 연결(name binding)해서 값을 저장할 수 있게 준비하는 것.
- 변수 사용을 위해서는 반드시 선언이 필요하다. 자바스크립트에서는 var, let, const 키워드.
cf. ES5 vs ES6 변수 선언 키워드
- var는 블록 레벨 스코프(block-level-scope)를 지원하지 않고 함수 레벨 스코프(function-level-scope)를 지원하기 때문에 의도치 않게 전역 변수가 선언되어 부작용이 발생할 수 있다는 단점이 있다.
- var 키워드 단점 보완을 위해 ES6에서 let, const 키워드를 도입했다.
- var 키워드가 폐기(deprecated) 된 것은 아니지만, ES6이후 사양에서는 권장x
cf. 변수의 생성과정
- 선언 단계
- 초기화 단계
- 할당 단계
let name;
name = "HAESUNG";
var age;
age = 30;
const gender; // 선언에서 초기화가 없는 오류
gender = 'male'
- var
- 선언 및 초기화 단계(undefined를 할당해주는 단계)
- 할당 단계
- let
- 선언
- 초기화
- 할당
- const
- 선언 + 초기화 + 할당
cf. 키워드(keyword)
-
키워드는 자바스크립트 코드를 해석하고 실행하는 자바스크립트 엔진이 수행할 동작을 규정한 일종의 명령어. 자바스크립트 엔진은 키워드를 만나면 수행해야 할 약속된 동작을 수행. ex) var키워드 뒤에 변수 이름으로 새로운 변수 선언.
-
변수 선언문은 아래와 같이 변수 이름을 등록하고 값을 저장할 메모리 공간을 확보한다.
var score // 변수 선언(변수 선언문)

- 변수 선언 후, 값 할당하지 않으면 확보된 메모리 공간에는 자바스크립트 엔진에 의해 undefined라는 값이 암묵적으로 할당되어 초기화 된다.(자바스크립트의 독특한 특징)
- 자바스크립트 엔진의 변수 선언 2단계
- 선언 단계 : 변수 이름을 등록해서 자바스크립트 엔진에 변수의 존재를 알린다.
- 초기화 단계 : 값을 저장하기 위한 메모리 공간을 확보하고 암묵적으로 undefined를 할당해 초기화 한다.
cf. 변수 이름은 어디에 등록 되는가?
- 변수 이름을 비롯한 모든 식별자는 실행 컨텍스트(execution context)에 등록 된다.
- 실행 컨텍스트는 자바스크립트 엔진이 소스코드를 평가하고 실행하기 위한 필요 환경을 제공하고 코드 실행결과를 실제로 관리하는 영역
- 자바스크립트 엔진은 실행컨텍스트를 통해 식별자와 스코프를 관리.
- 변수 이름과 값은 실행컨텍스트 내 key / value 형식인 객체로 등록되어 관리 된다.
- var 키워드를 사용한 변수 선언은 선언 단계와 초기화 단계가 동시 진행.
- var score;는 선언 단계를 통해 변수 이름 score를 등록,
- 초기화 단계를 통해 score 변수에 암묵적으로 undefined를 할당해 초기화
- 초기화 단계를 거치지 않으면 확보된 메모리 공간에는 이전 애플리케이션이 사용했던 쓰레기 값(garbage value) 이 남아 있을 수 있다. 따라서, var 키워드로 선언한 변수는 암묵적으로 값을 할당하지 않아도 undefined 값으로 초기화를 하기 때문에 이런 위험으로부터 안전
- cf. 초기화(initialization) - 변수가 선언된 이후 최초로 값을 할당하는 것
- 변수를 사용하려면 반드시 선언이 필요하며 변수뿐만 아니라 모든 식별자도 동일
- 만약 선언하지 않은 식별자에 접근하면 ReferenceError(참조 에러) 가 발생한다.
- 참조 에러 - 식별자를 통해 값 참조 시, 자바스크립트 엔진이 등록된 식별자를 찾을 수 없을 때 발생하는 에러
4.4 변수 선언의 실행 시점과 변수 호이스팅
console.log(score); // undefined
var score; // 변수 선언문
- 자바스크립트는 인터프리터에 의해 한줄 씩 순차적을 실행되므로 console.log(score)가 참조 에러가 발생할 것처럼 보인다. 하지만, undefined가 출력된다.
- 이는 변수 선언이 소스코드가 한줄 씩 순차적으로 실행되는 시점, 즉 런타임(runtime)이 아니라 그 이전 단계에서 소스코드 평가 과정에서 모든 선언문을 먼저 실행하기 때문이다.
- 변수 호이스팅(variable hoisting) - 변수 선언문이 코드의 선두로 끌어 올려진 것처럼 동작하는 자바스크립트 고유 특징
- 변수 선언뿐 아니라 var, let, const, function ,function*, class 키워드 사용해서 선언하는 모든 식별자(변수, 함수, 클래스 등)는 호이스팅 된다.
4.5 값의 할당
- 변수에 값을 할당(assignmnet)할 때는 할당 연산자 =를 사용
- 할당 연산자는 우변의 값을 좌변의 변수에 할당
var score; //변수 선언
score = 80; // 값의 할당
- 변수 선언과 값의 할당을 하나의 문(statement)로 단축 표현 가능
var score = 80; // 변수 선언과 값 할당
-
변수 선언과 값 할당을 2개의 문으로 나누어 각각 실행하기 때문에 변수 선언, 값 할당을 2개의 문으로 나눈 코드와 하나의 문으로 단축 표현한 코드 모두 동일하게 동작.
-
변수 선언과 값 할당의 실행 시점이 다르다.
-
변수 선언은 소스코드가 순차적으로 실행되는 시점인 런타임 이전에 먼저 실행
-
값의 할당은 소스코드가 순차적으로 실행되는 시점인 런타임에 실행
console.log(score); //undefined var score; // 1. 변수선언 score = 80; // 2. 값 할당 console.log(score); // 80
-
-
위에서 변수 값 할당할 때는 undefined가 저장된 공간이 아니라 새로운 메모리 공간을 확보하고 그곳에 할당 값을 저장한다. 이전 값 undefined가 저장되어 있던 메모리 공간을 지우고 그 공간에 할당 값을 새롭게 저장하는게 아니다.
console.log(score); //undefined score = 80; // 값 할당 var score; // 변수 선언 console.log(score); //80
4.6 값의 재할당
- 재할당 - 이미 값 할당되어 있는 변수에 새로운 값을 또다시 할당하는 것
var score = 80;
score = 90;
- var 키워드로 선언한 변수는 값을 재할당 할 수 있다.
- var 키워드로 선언한 변수는 선언과 동시에 undefined로 초기화되므로 엄밀히 말하면 처음 값을 할당하는 것도 재할당이라고 볼 수 있다.
- 상수(constant) - 값을 재할당할 수 없어서 변수에 저장된 값을 변경할 수 없는 값, 한번만 할당할 수 있는 변수
cf. const 키워드
-
ES6에서 도입된 const 키워드를 사용해 선언한 변수는 재할당 금지.
-
score 변수는 처음 undefined로 초기화 후, 80이 할당되고 90으로 재할당되면서 undefined와 80은 어떤 변수도 값으로 갖고 있지 않아 연결된 식별자가 없다. 이런 불필요한 값들은 가비지 콜렉터(garbage collector) 에 의해 메모리에서 자동 해제 된다.

cf. 가비지 콜렉터
- 애플리케이션이 할당한 메모리 공간을 주기적으로 검사하여 더이상 사용되지 않는 메모리(어떤 식별자도 참조하지 않는 메모리 공간)를 해제하는 기능.
- 자바스크립트는 가비지 콜렉터를 내장하고 있는 매니지드 언어로서 가비지 콜렉터를 톨해 메모리 누수(memory leak)를 방지.
cf. 언 매니지드 언어(unmmanaged language)와 매니지드 언어(managed language)
- 메모리 관리 방식에 따라 언매니지드 언어와 매니지드 언어로 분류
- 언매니지드언어
- C언어 같은 언매니지드 언어는 개발자가 명시적으로 메모리를 할당하고 해제하기 위해 malloc()과 free() 같은 저수준(low-level) 메모리 제어 기능을 제공한다.
- 메모리 제어를 개발자가 주도할 수 있어 역량에 따라 최적 성능을 확보할 수 있다.
- 하지만, 반대로 치명적 오류를 생산할 가능성도 있음.
- 매니지드 언어
- 메모리 할당 및 해제를 위한 메모리 관리 기능을 언어 차원에서 담당
- 개발자의 직접적인 메모리 제어를 허용하지 않는다.
- 사용되지 않는 메모리 해제는 가비지 콜렉터가 수행
- 개발자의 역량에 의존하는 부분이 상대적으로 작아져 일정한 생산성을 확보할 수 있음
- 하지만, 성능 면에서 어느 정도 손실 감수해야한다는 단점 존재
4.7 식별자 네이밍 규칙
-
준수해야 할 식별자 네이밍 규칙
- 식별자는 특수문자를 제외한 문자, 숫자, 언더스코어(_), 달러 기호($)를 포함할 수 있다.
- 특수문자를 제외한 문자, 언더스코어(_), 달러기호($)로 시작해야한다. 숫자 시작 허용X
- 예약어는 식별자로 사용 X
-
변수 이름도 식별자이므로 네이밍 규칙을 준수해야 하지만, 다음과 같은 식별자는 변수 이름으로 사용 가능.
var person, $elem, _name, first_name, val1;
-
ES5부터 식별자를 만들 때 유니코드 문자 허용. 하지만 알파벳외 유니코드 문자로 명명된 식별자 사용하는 것은 x
var 이름, HAESUNG;
-
네이밍 컨벤션(naming convention) 은 하나 이상의 영어 단어로 구성된 식별자 만들 때, 가독성 좋게 단어를 구분하기 위해 규정한 명명 규칙. 4가지 유형의 네이밍 컨벤션이 자주 사용
// 카멜 케이스 (camelCase) var firstName; // 스네이크 케이스 (snake_case) var first_name; // 파스칼 케이스 (PascalCase) var FirstName; // 헝가리언 케이스 (typeHungarianCase) - 접두어에 자료형을 알아볼수 있게끔 표기하는 것 var strFirstName; // type + identifier var $elem = document.getElementById('myId'); // DOM 노드 var observable$ = fromEvent(document, 'click'); // RxJS 옵저버블
-
어떤 네이밍 컨벤션을 사용해도 좋고 일관성 유지가 중요하지만,
자바스크립트에서 일반적으로 카멜 케이스 - 변수나 함수, 파스칼 케이스 - 생성자 함수, 클래스와 같이 사용한다. (ECMAScript 사양 정의 된 객체 함수도 카멜케이스와 파스칼 케이스 사용)
출처
- 이웅모, 『모던 자바스크립트 Deep Dive 자바스크립트의 기본 개념과 동작 원리』, 위키북스(2020).